/**** Hardware Control Functions  ********************************************************************************
These functions control ports, timers, and PWM bit-banging
*****************************************************************************************************************/

// Initialize LED control ports and timer2 settings (8-bit)
void InitIO() {
  // Initialize 6 PORTB outputs for on/off control of adjacent LED pair cathodes
  // LEDs are numbered D1..D12.  B0=D1+D2, B1=D3+D4, B2=D4+D6, etc.
  DDRB |=   ((1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)); 
  // set all cathodes HIGH --> all LEDs off
  PORTB &= ~AllOn;
  // Initialize 3 PORTC outputs for RGB color channel B anodes (even LEDs)
  DDRC |= BLED;
  // PORTC4 and PORTC5 are for I2C communication. Disable internal pullups.
  PORTC &= ~((1<<4)|(1<<5)); 
  // Initialize 3 PORTD outputs for RGB color channel A anodes (odd LEDs)
  DDRD |= ALED;
  // Turn off all LEDs
  set_all_rgb(0,0,0);
  
  // Timer2 Settings
  // Set timer2 prescaler (frequency divider)
  // 8 prescaler gives 7.8 kHz counter for software bit-bang PWM
  TCCR2B |= ((0 << CS20) | (1 << CS21) | (0 << CS22));
  // normal mode
  TCCR2B &= ~(1 << WGM22);
  TCCR2A =0;
  // enable timer2 overflow
  TIMSK2 |= (1 << TOIE2);
}

//The timer2 overflow ISR will run with every counter cycle
ISR (TIMER2_OVF_vect) {
  uint8_t b,t,l,tmp;
  static uint8_t transistor[6]={0x01,0x02,0x04,0x08,0x10,0x20}; //cathode on/off transistor selection (hex format)
  sei(); // it's important to release the CPU as soon as possible to not freeze I2C communications
  
  // bit-bang PWM cycle through each color port
  for (t=0;t<6;t++) {
    PORTB=transistor[t];
    l=2*t;
    for (b=0;b<255;b++) {
      tmp=0;
      if (b < brightness[0][l])   
        tmp |= (1 << RedA);  
      else 
        tmp &= ~(1 << RedA);
      if (b < brightness[0][l+1]) 
        tmp |= (1 << RedB);  
      else 
        tmp &= ~(1 << RedB);
      if (b < brightness[1][l])   
        tmp |= (1 << GreenA);  
      else 
        tmp &= ~(1 << GreenA);
      if (b < brightness[1][l+1]) 
        tmp |= (1 << GreenB);  
      else 
        tmp &= ~(1 << GreenB);
      if (b < brightness[2][l])   
        tmp |= (1 << BlueA);  
      else 
        tmp &= ~(1 << BlueA);
      if (b < brightness[2][l+1]) 
        tmp |= (1 << BlueB);  
      else 
        tmp &= ~(1 << BlueB);
      // set output registers  
      PORTC = tmp; 
      PORTD = tmp|0x18;  // need to always reconfigure D3 and D4 as inputs (Switches)
    }
  }
  TCNT2 = 254; // reset the counter
}


